return image;
}
-GskVulkanImage *
-gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self,
- GskVulkanUploader *uploader,
- PangoFont *font,
- PangoGlyphString *glyphs)
-{
- if (self->glyph_cache->image == NULL)
- self->glyph_cache->image = gsk_vulkan_image_new_from_data (uploader,
- cairo_image_surface_get_data (self->glyph_cache->surface),
- cairo_image_surface_get_width (self->glyph_cache->surface),
- cairo_image_surface_get_height (self->glyph_cache->surface),
- cairo_image_surface_get_stride (self->glyph_cache->surface));
-
- return g_object_ref (self->glyph_cache->image);
-}
-
typedef struct _GlyphCacheKey GlyphCacheKey;
typedef struct _GlyphCacheValue GlyphCacheValue;
PangoGlyph glyph;
};
-struct _GlyphCacheValue {
- float tx;
- float ty;
- float tw;
- float th;
-
- float draw_x;
- float draw_y;
- float draw_width;
- float draw_height;
-};
-
-static GlyphCacheValue *glyph_cache_lookup (GlyphCache *cache,
- gboolean create,
- PangoFont *font,
- PangoGlyph glyph);
-
-void
-gsk_vulkan_renderer_get_glyph_coords (GskVulkanRenderer *self,
- PangoFont *font,
- PangoGlyph glyph,
- float *tx,
- float *ty,
- float *tw,
- float *th,
- float *dx,
- float *dy,
- float *dw,
- float *dh)
-{
- GlyphCacheValue *gv;
-
- gv = glyph_cache_lookup (self->glyph_cache, FALSE, font, glyph);
-
- if (gv)
- {
- *tx = gv->tx;
- *ty = gv->ty;
- *tw = gv->tw;
- *th = gv->th;
- *dx = gv->draw_x;
- *dy = gv->draw_y;
- *dw = gv->draw_width;
- *dh = gv->draw_height;
- }
-}
-
/*** Glyph cache ***/
static gboolean
}
static void
-add_to_cache (GlyphCache *cache,
- PangoFont *font,
- PangoGlyph glyph,
- GlyphCacheValue *value)
+add_to_cache (GlyphCache *cache,
+ PangoFont *font,
+ PangoGlyph glyph,
+ GskVulkanCachedGlyph *value)
{
cairo_t *cr;
cairo_scaled_font_t *scaled_font;
value->ty = (cg.y + value->draw_y) / cache->height;
value->tw = (float)value->draw_width / cache->width;
value->th = (float)value->draw_height / cache->height;
+
+ value->texture_index = 0;
}
-static GlyphCacheValue *
+static GskVulkanCachedGlyph *
glyph_cache_lookup (GlyphCache *cache,
gboolean create,
PangoFont *font,
PangoGlyph glyph)
{
GlyphCacheKey lookup_key;
- GlyphCacheValue *value;
+ GskVulkanCachedGlyph *value;
lookup_key.font = font;
lookup_key.glyph = glyph;
GlyphCacheKey *key;
PangoRectangle ink_rect;
- value = g_new (GlyphCacheValue, 1);
+ value = g_new (GskVulkanCachedGlyph, 1);
+
+ value->texture_index = 0;
pango_font_get_glyph_extents (font, glyph, &ink_rect, NULL);
pango_extents_to_pixels (&ink_rect, NULL);
value->draw_height = ink_rect.height;
if (ink_rect.width > 0 && ink_rect.height > 0)
- {
- add_to_cache (cache, font, glyph, value);
-
- g_clear_object (&cache->image);
- }
+ add_to_cache (cache, font, glyph, value);
key = g_new (GlyphCacheKey, 1);
key->font = g_object_ref (font);
return value;
}
-void
-gsk_vulkan_renderer_cache_glyphs (GskVulkanRenderer *self,
- PangoFont *font,
- PangoGlyphString *glyphs)
+static void
+free_glyph_cache (GlyphCache *cache)
+{
+ g_hash_table_unref (cache->hash_table);
+ cairo_surface_destroy (cache->surface);
+ g_free (cache);
+}
+
+static void
+dump_glyph_cache_stats (GlyphCache *cache)
{
- int i;
+ static gint64 time;
+ gint64 now;
- for (i = 0; i < glyphs->num_glyphs; i++)
- {
- PangoGlyphInfo *gi = &glyphs->glyphs[i];
+ if (!cache->hash_table)
+ return;
- if (gi->glyph != PANGO_GLYPH_EMPTY)
- {
- if (!(gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG))
- (void) glyph_cache_lookup (self->glyph_cache, TRUE, font, gi->glyph);
- }
- }
+ now = g_get_monotonic_time ();
+ if (now - time < 1000000)
+ return;
+
+ time = now;
+
+ cairo_surface_write_to_png (cache->surface, "gsk-glyph-cache.png");
+}
+
+guint
+gsk_vulkan_renderer_cache_glyph (GskVulkanRenderer *self,
+ PangoFont *font,
+ PangoGlyph glyph)
+{
+ GskVulkanCachedGlyph *value;
+
+ value = glyph_cache_lookup (self->glyph_cache, TRUE, font, glyph);
+
+ return value->texture_index;
}
static GlyphCache *
return cache;
}
-static void
-free_glyph_cache (GlyphCache *cache)
+GskVulkanImage *
+gsk_vulkan_renderer_ref_glyph_image (GskVulkanRenderer *self,
+ GskVulkanUploader *uploader,
+ guint index)
{
- g_hash_table_unref (cache->hash_table);
- cairo_surface_destroy (cache->surface);
- g_free (cache);
+ if (self->glyph_cache->image == NULL)
+ self->glyph_cache->image = gsk_vulkan_image_new_from_data (uploader,
+ cairo_image_surface_get_data (self->glyph_cache->surface),
+ cairo_image_surface_get_width (self->glyph_cache->surface),
+ cairo_image_surface_get_height (self->glyph_cache->surface),
+ cairo_image_surface_get_stride (self->glyph_cache->surface));
+
+ return g_object_ref (self->glyph_cache->image);
}
-static void
-dump_glyph_cache_stats (GlyphCache *cache)
+GskVulkanCachedGlyph *
+gsk_vulkan_renderer_get_cached_glyph (GskVulkanRenderer *self,
+ PangoFont *font,
+ PangoGlyph glyph)
{
- static gint64 time;
- gint64 now;
-
- if (!cache->hash_table)
- return;
-
- now = g_get_monotonic_time ();
- if (now - time < 1000000)
- return;
+ GlyphCacheKey lookup_key;
- time = now;
+ lookup_key.font = font;
+ lookup_key.glyph = glyph;
- cairo_surface_write_to_png (cache->surface, "gsk-glyph-cache.png");
+ return g_hash_table_lookup (self->glyph_cache->hash_table, &lookup_key);
}
typedef union _GskVulkanOp GskVulkanOp;
typedef struct _GskVulkanOpRender GskVulkanOpRender;
+typedef struct _GskVulkanOpText GskVulkanOpText;
typedef struct _GskVulkanOpPushConstants GskVulkanOpPushConstants;
typedef enum {
gsize descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
};
+struct _GskVulkanOpText
+{
+ GskVulkanOpType type;
+ GskRenderNode *node; /* node that's the source of this op */
+ GskVulkanPipeline *pipeline; /* pipeline to use */
+ GskRoundedRect clip; /* clip rect (or random memory if not relevant) */
+ GskVulkanImage *source; /* source image to render */
+ gsize vertex_offset; /* offset into vertex buffer */
+ gsize vertex_count; /* number of vertices */
+ gsize descriptor_set_index; /* index into descriptor sets array for the right descriptor set to bind */
+ guint texture_index;
+ guint start_glyph;
+ guint num_glyphs;
+};
+
struct _GskVulkanOpPushConstants
{
GskVulkanOpType type;
GskVulkanOpType type;
GskVulkanOpRender render;
GskVulkanOpPushConstants constants;
+ GskVulkanOpText text;
};
struct _GskVulkanRenderPass
return;
case GSK_TEXT_NODE:
- gsk_vulkan_renderer_cache_glyphs (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
- gsk_text_node_get_font (node),
- gsk_text_node_get_glyphs (node));
+ {
+ PangoFont *font = gsk_text_node_get_font (node);
+ PangoGlyphString *glyphs = gsk_text_node_get_glyphs (node);
+ PangoGlyph glyph;
+ int i;
+ guint texture_index;
+ GskVulkanRenderer *renderer = GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render));
+
+ if (font_has_color_glyphs (font))
+ {
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED;
+ else
+ FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_COLOR_TEXT;
+ }
+ else
+ {
+ if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXT;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP;
+ else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
+ pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED;
+ else
+ FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
+ op.type = GSK_VULKAN_OP_TEXT;
+ }
+ op.text.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- if (font_has_color_glyphs (gsk_text_node_get_font (node)))
- {
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_COLOR_TEXT_CLIP_ROUNDED;
- else
- FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_COLOR_TEXT;
- }
- else
- {
- if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
- pipeline_type = GSK_VULKAN_PIPELINE_TEXT;
- else if (constants->clip.type == GSK_VULKAN_CLIP_RECT)
- pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP;
- else if (constants->clip.type == GSK_VULKAN_CLIP_ROUNDED_CIRCULAR)
- pipeline_type = GSK_VULKAN_PIPELINE_TEXT_CLIP_ROUNDED;
- else
- FALLBACK ("Text nodes can't deal with clip type %u\n", constants->clip.type);
- op.type = GSK_VULKAN_OP_TEXT;
- }
- op.render.pipeline = gsk_vulkan_render_get_pipeline (render, pipeline_type);
- g_array_append_val (self->render_ops, op);
- return;
+ i = 0;
+ texture_index = gsk_vulkan_renderer_cache_glyph (renderer, font, glyphs->glyphs[0].glyph);
+ while (i < glyphs->num_glyphs)
+ {
+ op.text.start_glyph = i;
+ op.text.texture_index = texture_index;
+
+ do {
+ i++;
+ glyph = glyphs->glyphs[i].glyph;
+ if (glyph != PANGO_GLYPH_EMPTY && !(glyph & PANGO_GLYPH_UNKNOWN_FLAG))
+ texture_index = gsk_vulkan_renderer_cache_glyph (renderer, font, glyph);
+ } while (i < glyphs->num_glyphs && op.text.texture_index == texture_index);
+
+ op.text.num_glyphs = i - op.text.start_glyph;
+ g_array_append_val (self->render_ops, op);
+ }
+ return;
+ }
case GSK_TEXTURE_NODE:
if (gsk_vulkan_clip_contains_rect (&constants->clip, &node->bounds))
case GSK_VULKAN_OP_TEXT:
case GSK_VULKAN_OP_COLOR_TEXT:
{
- op->render.source = gsk_vulkan_renderer_ref_glyph_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
- uploader,
- gsk_text_node_get_font (op->render.node),
- gsk_text_node_get_glyphs (op->render.node));
- gsk_vulkan_render_add_cleanup_image (render, op->render.source);
+ op->text.source = gsk_vulkan_renderer_ref_glyph_image (GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
+ uploader,
+ op->text.texture_index);
+ gsk_vulkan_render_add_cleanup_image (render, op->text.source);
}
break;
break;
case GSK_VULKAN_OP_TEXT:
- op->render.vertex_count = gsk_vulkan_text_pipeline_count_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->render.pipeline),
- pango_glyph_string_num_glyphs (gsk_text_node_get_glyphs (op->render.node)));
- n_bytes += op->render.vertex_count;
+ op->text.vertex_count = gsk_vulkan_text_pipeline_count_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
+ op->text.num_glyphs);
+ n_bytes += op->text.vertex_count;
break;
case GSK_VULKAN_OP_COLOR_TEXT:
- op->render.vertex_count = gsk_vulkan_color_text_pipeline_count_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->render.pipeline),
- pango_glyph_string_num_glyphs (gsk_text_node_get_glyphs (op->render.node)));
- n_bytes += op->render.vertex_count;
+ op->text.vertex_count = gsk_vulkan_color_text_pipeline_count_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->render.pipeline),
+ op->text.num_glyphs);
+ n_bytes += op->text.vertex_count;
break;
case GSK_VULKAN_OP_COLOR:
case GSK_VULKAN_OP_TEXT:
{
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_text_pipeline_collect_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->render.pipeline),
+ op->text.vertex_offset = offset + n_bytes;
+ gsk_vulkan_text_pipeline_collect_vertex_data (GSK_VULKAN_TEXT_PIPELINE (op->text.pipeline),
data + n_bytes + offset,
GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
- &op->render.node->bounds,
- gsk_text_node_get_font (op->render.node),
- gsk_text_node_get_glyphs (op->render.node),
- gsk_text_node_get_color (op->render.node),
- gsk_text_node_get_x (op->render.node),
- gsk_text_node_get_y (op->render.node));
- n_bytes += op->render.vertex_count;
+ &op->text.node->bounds,
+ gsk_text_node_get_font (op->text.node),
+ gsk_text_node_get_glyphs (op->text.node),
+ gsk_text_node_get_color (op->text.node),
+ gsk_text_node_get_x (op->text.node),
+ gsk_text_node_get_y (op->text.node),
+ op->text.start_glyph,
+ op->text.num_glyphs);
+ n_bytes += op->text.vertex_count;
}
break;
case GSK_VULKAN_OP_COLOR_TEXT:
{
- op->render.vertex_offset = offset + n_bytes;
- gsk_vulkan_color_text_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->render.pipeline),
+ op->text.vertex_offset = offset + n_bytes;
+ gsk_vulkan_color_text_pipeline_collect_vertex_data (GSK_VULKAN_COLOR_TEXT_PIPELINE (op->text.pipeline),
data + n_bytes + offset,
GSK_VULKAN_RENDERER (gsk_vulkan_render_get_renderer (render)),
- &op->render.node->bounds,
- gsk_text_node_get_font (op->render.node),
- gsk_text_node_get_glyphs (op->render.node),
- gsk_text_node_get_x (op->render.node),
- gsk_text_node_get_y (op->render.node));
- n_bytes += op->render.vertex_count;
+ &op->text.node->bounds,
+ gsk_text_node_get_font (op->text.node),
+ gsk_text_node_get_glyphs (op->text.node),
+ gsk_text_node_get_x (op->text.node),
+ gsk_text_node_get_y (op->text.node),
+ op->text.start_glyph,
+ op->text.num_glyphs);
+ n_bytes += op->text.vertex_count;
}
break;
case GSK_VULKAN_OP_FALLBACK_CLIP:
case GSK_VULKAN_OP_FALLBACK_ROUNDED_CLIP:
case GSK_VULKAN_OP_SURFACE:
- case GSK_VULKAN_OP_TEXT:
- case GSK_VULKAN_OP_COLOR_TEXT:
case GSK_VULKAN_OP_TEXTURE:
case GSK_VULKAN_OP_OPACITY:
case GSK_VULKAN_OP_BLUR:
op->render.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->render.source);
break;
+ case GSK_VULKAN_OP_TEXT:
+ case GSK_VULKAN_OP_COLOR_TEXT:
+ op->text.descriptor_set_index = gsk_vulkan_render_reserve_descriptor_set (render, op->text.source);
+ break;
default:
g_assert_not_reached ();
case GSK_VULKAN_OP_COLOR:
break;
case GSK_VULKAN_OP_TEXT:
- if (current_pipeline != op->render.pipeline)
+ if (current_pipeline != op->text.pipeline)
{
- current_pipeline = op->render.pipeline;
+ current_pipeline = op->text.pipeline;
vkCmdBindPipeline (command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS,
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
(VkBuffer[1]) {
gsk_vulkan_buffer_get_buffer (vertex_buffer)
},
- (VkDeviceSize[1]) { op->render.vertex_offset });
+ (VkDeviceSize[1]) { op->text.vertex_offset });
current_draw_index = 0;
}
0,
1,
(VkDescriptorSet[1]) {
- gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
+ gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
},
0,
NULL);
current_draw_index += gsk_vulkan_text_pipeline_draw (GSK_VULKAN_TEXT_PIPELINE (current_pipeline),
- command_buffer,
- current_draw_index, pango_glyph_string_num_glyphs (gsk_text_node_get_glyphs (op->render.node)));
+ command_buffer,
+ current_draw_index, op->text.num_glyphs);
break;
case GSK_VULKAN_OP_COLOR_TEXT:
- if (current_pipeline != op->render.pipeline)
+ if (current_pipeline != op->text.pipeline)
{
- current_pipeline = op->render.pipeline;
+ current_pipeline = op->text.pipeline;
vkCmdBindPipeline (command_buffer,
VK_PIPELINE_BIND_POINT_GRAPHICS,
gsk_vulkan_pipeline_get_pipeline (current_pipeline));
(VkBuffer[1]) {
gsk_vulkan_buffer_get_buffer (vertex_buffer)
},
- (VkDeviceSize[1]) { op->render.vertex_offset });
+ (VkDeviceSize[1]) { op->text.vertex_offset });
current_draw_index = 0;
}
0,
1,
(VkDescriptorSet[1]) {
- gsk_vulkan_render_get_descriptor_set (render, op->render.descriptor_set_index)
+ gsk_vulkan_render_get_descriptor_set (render, op->text.descriptor_set_index)
},
0,
NULL);
current_draw_index += gsk_vulkan_color_text_pipeline_draw (GSK_VULKAN_COLOR_TEXT_PIPELINE (current_pipeline),
command_buffer,
- current_draw_index, pango_glyph_string_num_glyphs (gsk_text_node_get_glyphs (op->render.node)));
+ current_draw_index, op->text.num_glyphs);
break;
case GSK_VULKAN_OP_OPACITY: